package com.eastfair.venuebooking.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.eastfair.boot.service.SuperServiceImpl;
import com.eastfair.constant.BusinessConstant;
import com.eastfair.core.base.R;
import com.eastfair.core.context.ContextUtil;
import com.eastfair.core.exception.BizException;
import com.eastfair.core.utils.ConvertUtil;
import com.eastfair.venuebooking.dao.FollowRecordMapper;
import com.eastfair.venuebooking.dto.FollowRecordPlanSaveDTO;
import com.eastfair.venuebooking.dto.FollowRecordQuery;
import com.eastfair.venuebooking.dto.FollowRecordTimelineQuery;
import com.eastfair.venuebooking.entity.FollowRecord;
import com.eastfair.venuebooking.enums.VenueBookingMoudleEnum;
import com.eastfair.venuebooking.service.*;
import com.eastfair.venuebooking.vo.FollowRecordTimelineVO;
import com.eastfair.venuebooking.vo.FollowRecordVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 业务实现类
 * 跟进记录表
 * </p>
 *
 * @author clm
 * @date 2022-06-11
 */
@Slf4j
@Service
public class FollowRecordServiceImpl extends SuperServiceImpl<FollowRecordMapper, FollowRecord> implements FollowRecordService {

    @Resource
    private FollowRecordMapper followRecordMapper;

    @Resource
    private FollowPlanService followPlanService;

    @Resource
    private CustomerMainService customerMainService;

    @Resource
    private SaleClueService saleClueService;

    @Resource
    private BusinessOpportunityService businessOpportunityService;

    @Resource
    private ContractManageService contractManageService;

    @Resource
    private VenueBookingUserAccountService venueBookingUserAccountService;

    private static final String NEXT_START_DATE = "nextStartDate";

    private static final String INIT_NEXT_START_DATE = "0";

    private static final int FOLLOW_DATE_SIZE = 3;

    /**
     * 处理逻辑删除相关处理
     *
     * @param modelList 实体
     * @return 是否成功
     */
    @Override
    protected R<Boolean> handlerRemoveByIdsOfLogic(Collection<FollowRecord> modelList) {
        modelList.forEach(s -> {
            s.setIsDeleted(BusinessConstant.YES);
        });
        // TODO: 2021/10/29 这里需要操作其他业务，如清空角色等
        return R.successDef();
    }

    @Override
    protected R<Boolean> handlerSave(FollowRecord model) {
        model.setProjectId(ContextUtil.getProjectId());
        model.setTenantId(ContextUtil.getTenantId());
        model.setSubsystemId(ContextUtil.getSubSystemId());
        if (model.getFollowDate() == null) {
            model.setFollowDate(model.getFollowDateTime().toLocalDate());
        }
        return R.successDef();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveFollowRecordPlan(FollowRecordPlanSaveDTO saveDTO) {
        log.info("saveFollowRecordPlan - 新增跟进记录, saveDTO={}", saveDTO);

        // 更新各个业务表跟进信息
        if (VenueBookingMoudleEnum.CUSTOMER.getCode().equals(saveDTO.getFollowRecordType())) {
            customerMainService.updateFollow(saveDTO);
        } else if (VenueBookingMoudleEnum.SALE_CLUE.getCode().equals(saveDTO.getFollowRecordType())) {
            saleClueService.updateFollow(saveDTO);
        } else if (VenueBookingMoudleEnum.BUSINESS_OPPORTUNITY.getCode().equals(saveDTO.getFollowRecordType())) {
            businessOpportunityService.updateFollow(saveDTO);
        } else if (VenueBookingMoudleEnum.CONTRACT_MANAGE.getCode().equals(saveDTO.getFollowRecordType())) {
            contractManageService.updateFollow(saveDTO);
        } else {
            throw BizException.validFail("跟进记录类型参数错误");
        }
        // 保存跟进计划
        if (saveDTO.getIsPlanFollow() != null && saveDTO.getIsPlanFollow()) {
            if (saveDTO.getFollowPlanSaveDTO() == null) {
                throw BizException.validFail("跟进计划不可为空");
            }
            followPlanService.saveFollowPlan(saveDTO.getFollowPlanSaveDTO());
        }
        // 保存跟进记录
        FollowRecord followRecord = BeanUtil.toBean(saveDTO, FollowRecord.class);
        return save(followRecord);
    }

    @Override
    public List<FollowRecordVO> listFollowRecords(FollowRecordQuery query) {
        QueryWrapper<FollowRecord> queryWrapper = createFollowRecordQueryWrapper(query);
        List<FollowRecord> followRecordList = list(queryWrapper);
        if (followRecordList == null || followRecordList.isEmpty()) {
            return Collections.emptyList();
        }
        // 查询账户信息
        List<Long> followUserIds = followRecordList
                .stream()
                .map(FollowRecord::getFollowUserId)
                .collect(Collectors.toList());
        Map<Long, String> userMap = venueBookingUserAccountService.listUserAccount(followUserIds);
        // 转换数据
        return followRecordList
                .stream()
                .map(followRecord -> {
                    FollowRecordVO followRecordVO = BeanUtil.toBean(followRecord, FollowRecordVO.class);
                    String followUserId = userMap.get(followRecordVO.getFollowUserId());
                    followRecordVO.setFollowUserName(followUserId);
                    return followRecordVO;
                })
                .collect(Collectors.toList());
    }

    @Override
    public R<List<FollowRecordTimelineVO>> listFollowRecordTimelineVOs(FollowRecordTimelineQuery query) {
        if (StrUtil.isBlank(query.getNextStartDate())) {
            return R.<List<FollowRecordTimelineVO>>successDef()
                    .put(NEXT_START_DATE, null);
        }
        // 查询所有时间
        FollowRecordQuery followRecordQuery = BeanUtil.toBean(query, FollowRecordQuery.class);
        QueryWrapper<FollowRecord> queryWrapper = createCommonQueryWrapper(followRecordQuery);
        List<String> followDateList = followRecordMapper.listFollowDates(queryWrapper);
        if (followDateList == null || followDateList.isEmpty()) {
            return R.<List<FollowRecordTimelineVO>>successDef()
                    .put(NEXT_START_DATE, null);
        }
        // 获取当前查询的时间段
        List<String> followDatePeriod = getFollowDatePeriod(query.getNextStartDate(), followDateList);
        if (followDatePeriod.isEmpty()) {
            return R.<List<FollowRecordTimelineVO>>successDef()
                    .put(NEXT_START_DATE, null);
        }
        // 查询跟进记录
        followRecordQuery.setStartFollowDate(followDatePeriod.get(followDatePeriod.size() - 1));
        followRecordQuery.setEndFollowDate(followDatePeriod.get(0));
        List<FollowRecordVO> followRecordList = listFollowRecords(followRecordQuery);
        // 组装数据
        List<FollowRecordTimelineVO> voList = assembleFollowRecordTimelineVOs(followRecordList);
        if (voList.isEmpty()) {
            return R.successDef(voList)
                    .put(NEXT_START_DATE, null);
        }
        return R.successDef(voList)
                .put(NEXT_START_DATE, voList.get(voList.size() - 1).getTime());
    }

    @Override
    public long countFollowRecordByCustomerId(Long customerId) {
        log.info("countFollowRecordByCustomerId - 统计跟进记录数量, customerId={}", customerId);

        QueryWrapper<FollowRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(FollowRecord::getIsDeleted, BusinessConstant.DELETE_NO)
                .eq(customerId != null, FollowRecord::getCustomerId, customerId);
        return count(queryWrapper);
    }

    /**
     * @return com.eastfair.core.base.R<java.util.List < com.eastfair.venuebooking.vo.FollowRecordTimelineVO>>
     * @Author clm
     * @Description //获取未同步的跟进记录
     * @Date 10:10 2023/2/1
     * @Param []
     **/
    @Override
    public List<FollowRecordVO> listUnsynRecord() {

        QueryWrapper<FollowRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("sync_state", 0);
        List<FollowRecord> followRecords = baseMapper.selectList(queryWrapper);
        if (CollectionUtil.isEmpty(followRecords)){
            return new ArrayList<>();
        }
        List<FollowRecordVO> followRecordVOS = ConvertUtil.convertList(followRecords, FollowRecordVO.class);
        List<Long> ids = followRecordVOS.stream().map(FollowRecordVO::getId).collect(Collectors.toList());
        LambdaUpdateWrapper<FollowRecord> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.set(FollowRecord::getSyncState, 1);
        lambdaUpdateWrapper.in(FollowRecord::getId, ids);
        update(lambdaUpdateWrapper);
        return followRecordVOS;
    }

    /**
     * 获取当前查询的时间范围
     *
     * @param nextStartTime  查询开始时间
     * @param followDateList 跟进时间列表
     * @return 当前查询的时间范围.
     */
    private List<String> getFollowDatePeriod(String nextStartTime, List<String> followDateList) {
        int followDateListSize = followDateList.size();
        // 首次查询
        if (INIT_NEXT_START_DATE.equals(nextStartTime)) {
            return followDateList.subList(0, Math.min(FOLLOW_DATE_SIZE, followDateListSize));
        }
        // 非首次查询
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate nextStartDate = LocalDate.parse(nextStartTime, dateTimeFormatter);
        for (String followDateString : followDateList) {
            LocalDate followDate = LocalDate.parse(followDateString, dateTimeFormatter);
            if (nextStartDate.isAfter(followDate)) {
                int start = followDateList.indexOf(followDateString);
                return followDateList.subList(start, Math.min(start + FOLLOW_DATE_SIZE, followDateListSize));
            }
        }
        return Collections.emptyList();
    }

    /**
     * 跟进记录转为时间轴格式
     *
     * @param followRecordList 跟进记录列表
     * @return 时间轴列表
     */
    private List<FollowRecordTimelineVO> assembleFollowRecordTimelineVOs(List<FollowRecordVO> followRecordList) {
        if (followRecordList == null || followRecordList.isEmpty()) {
            return Collections.emptyList();
        }
        // 按照日期分组
        Map<String, List<FollowRecordVO>> followRecordGroup = followRecordList
                .stream()
                .collect(Collectors.groupingBy(followRecord -> followRecord.getFollowDate().toString()));
        // 按照日期倒序排列
        TreeMap<String, List<FollowRecordVO>> sortFollowRecordGroup
                = new TreeMap<>((o1, o2) -> Comparator.<String>reverseOrder().compare(o1, o2));
        sortFollowRecordGroup.putAll(followRecordGroup);
        // 转换数据
        return sortFollowRecordGroup
                .entrySet()
                .stream()
                .map(entry -> {
                    FollowRecordTimelineVO vo = new FollowRecordTimelineVO();
                    vo.setTime(entry.getKey());
                    vo.setChildren(entry.getValue());
                    return vo;
                })
                .collect(Collectors.toList());
    }

    private QueryWrapper<FollowRecord> createCommonQueryWrapper(FollowRecordQuery query) {
        QueryWrapper<FollowRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .and(followRecordQueryWrapper -> followRecordQueryWrapper
                        .eq(query.getCustomerId() != null, "customer_id", query.getCustomerId())
                        .or()
                        .eq(query.getContactId() != null, "contact_id", query.getContactId())
                        .or()
                        .eq(query.getClueId() != null, "clue_id", query.getClueId())
                        .or()
                        .eq(query.getBusinessOpportunityId() != null,
                                "business_opportunity_id", query.getBusinessOpportunityId())
                        .or()
                        .eq(query.getContractManageId() != null,
                                "contract_manage_id", query.getContractManageId())
                );
        return queryWrapper;
    }

    /**
     * 创建跟进记录查询。
     *
     * @param query FollowRecordQuery
     * @return QueryWrapper
     */
    private QueryWrapper<FollowRecord> createFollowRecordQueryWrapper(FollowRecordQuery query) {
        QueryWrapper<FollowRecord> queryWrapper = createCommonQueryWrapper(query);
        queryWrapper.between(StrUtil.isNotBlank(query.getStartFollowDate())
                                && StrUtil.isNotBlank(query.getEndFollowDate()),
                        "follow_date", query.getStartFollowDate(), query.getEndFollowDate())
                .orderByAsc("follow_date_time");
        return queryWrapper;
    }
}
